package com.adopapa.wechatapi.application.service;

import java.io.File;
import java.util.List;

import org.apache.log4j.Logger;

import com.adopapa.wechatapi.domain.common.ResultMessage;
import com.adopapa.wechatapi.domain.media.DownloadMediaResult;
import com.adopapa.wechatapi.domain.media.UploadMediaResult;
import com.adopapa.wechatapi.domain.token.AccessToken;
import com.adopapa.wechatapi.domain.token.JsApiTicket;
import com.adopapa.wechatapi.enterprise.domain.Department;
import com.adopapa.wechatapi.enterprise.domain.EnterpriseResult;
import com.adopapa.wechatapi.enterprise.domain.JobResult;
import com.adopapa.wechatapi.enterprise.domain.Member;
import com.adopapa.wechatapi.enterprise.domain.OpenUserIdResult;
import com.adopapa.wechatapi.enterprise.domain.Tag;
import com.adopapa.wechatapi.enterprise.domain.activeMessage.ECustomerMessage;
import com.adopapa.wechatapi.enterprise.domain.chat.Chat;
import com.adopapa.wechatapi.enterprise.domain.chat.ChatMessage;
import com.adopapa.wechatapi.enterprise.domain.customerMessage.ECustomerServiceMessage;
import com.adopapa.wechatapi.util.ApiUrls;
import com.adopapa.wechatapi.util.JsonUtil;
import com.adopapa.wechatapi.util.WeChatUtil;

public class EWechatApi {

	private final static Logger logger = Logger.getLogger(EWechatApi.class);
	private final static int OK = 0;

	/**
	 * 获取access token
	 */
	public static AccessToken getAccessToken(String corpId, String corpSecret) throws Exception {
		String url = String.format(ApiUrls.EACCESS_TOKEN_URL, corpId, corpSecret);
		String result = WeChatUtil.httpsRequest(url, "GET", null);
		if (result != null) {
			// result = result.replace("access_token",
			// "token").replace("expires_in", "expiresIn");
			AccessToken token = JsonUtil.json2Bean(result, AccessToken.class);
			return token;
		}
		return null;

	}

	/**
	 * 获取部门列表
	 * 
	 * @param accessToken
	 * @param departmentId
	 * @return
	 * @throws Exception
	 */
	public static List<Department> getDepartments(String accessToken, String departmentId) throws Exception {
		String url = String.format(ApiUrls.DEPARTMENT_LIST_URL, accessToken, departmentId);
		String result = WeChatUtil.httpsRequest(url, "GET", null);
		logger.info(result);
		if (result != null) {
			EnterpriseResult enterpriseResult = JsonUtil.json2Bean(result, EnterpriseResult.class);
			return enterpriseResult.getDepartments();
		}
		return null;
	}

	/**
	 * 创建部门信息
	 * 
	 * @param accessToken
	 * @param department
	 * @return
	 * @throws Exception
	 */
	public static Department createDepartment(String accessToken, Department department) throws Exception {
		String url = String.format(ApiUrls.DEPARTMENT_CREATE_URL, accessToken);
		String result = WeChatUtil.httpsRequest(url, "POST", JsonUtil.bean2Json(department));
		logger.info(result);
		if (result != null) {
			EnterpriseResult enterpriseResult = JsonUtil.json2Bean(result, EnterpriseResult.class);
			department.setId(Long.valueOf(enterpriseResult.getId()));
			return department;
		}
		return null;
	}

	/**
	 * 更新部门信息
	 * 
	 * @param accessToken
	 * @param department
	 * @return
	 * @throws Exception
	 */
	public static boolean updateDepartment(String accessToken, Department department) throws Exception {
		String url = String.format(ApiUrls.DEPARTMENT_UPDATE_URL, accessToken);
		String result = WeChatUtil.httpsRequest(url, "POST", JsonUtil.bean2Json(department));
		logger.info(result);
		if (result != null) {
			ResultMessage resultMessage = JsonUtil.json2Bean(result, ResultMessage.class);
			return OK == resultMessage.getErrcode();
		}
		return false;
	}

	/**
	 * 删除部门
	 * 
	 * @param accessToken
	 * @param departmentId
	 * @return
	 * @throws Exception
	 */
	public static boolean deleteDepartment(String accessToken, String departmentId) throws Exception {
		String url = String.format(ApiUrls.DEPARTMENT_DELETE_URL, accessToken, departmentId);
		String result = WeChatUtil.httpsRequest(url, "GET", null);
		logger.info(result);
		if (result != null) {
			ResultMessage resultMessage = JsonUtil.json2Bean(result, ResultMessage.class);
			return OK == resultMessage.getErrcode();
		}
		return false;
	}

	/**
	 * 按部门获取成员简单信息
	 * 
	 * @param accessToken
	 * @param departmentId
	 * @param fetchChild
	 * @param status
	 * @return
	 * @throws Exception
	 */
	public static List<Member> getSimpleMembersByDepartment(String accessToken, String departmentId, int fetchChild, int status) throws Exception {
		String url = String.format(ApiUrls.MEMBER_SIMPLE_LIST_URL, accessToken, departmentId, fetchChild, status);
		String result = WeChatUtil.httpsRequest(url, "GET", null);
		logger.info(result);
		if (result != null) {
			EnterpriseResult enterpriseResult = JsonUtil.json2Bean(result, EnterpriseResult.class);
			return enterpriseResult.getMembers();
		}
		return null;

	}

	/**
	 * 按部门获取成员详细信息
	 * 
	 * @param accessToken
	 * @param departmentId
	 * @param fetchChild
	 * @param status
	 * @return
	 * @throws Exception
	 */
	public static List<Member> getMembersByDepartment(String accessToken, String departmentId, int fetchChild, int status) throws Exception {
		String url = String.format(ApiUrls.MEMBER_LIST_URL, accessToken, departmentId, fetchChild, status);
		String result = WeChatUtil.httpsRequest(url, "GET", null);
		logger.info(result);
		if (result != null) {
			EnterpriseResult enterpriseResult = JsonUtil.json2Bean(result, EnterpriseResult.class);
			return enterpriseResult.getMembers();
		}
		return null;

	}

	/**
	 * 获取成员信息
	 * 
	 * @param accessToken
	 * @param userId
	 * @return
	 * @throws Exception
	 */
	public static Member getMember(String accessToken, String userId) throws Exception {
		String url = String.format(ApiUrls.MEMBER_GET_URL, accessToken, userId);
		String result = WeChatUtil.httpsRequest(url, "GET", null);
		logger.info(result);
		if (result != null) {
			Member member = JsonUtil.json2Bean(result, Member.class);
			return member;
		}
		return null;
	}

	/**
	 * 新增成员
	 * 
	 * @param accessToken
	 * @param member
	 * @return
	 * @throws Exception
	 */
	public static boolean createMember(String accessToken, Member member) throws Exception {
		String url = String.format(ApiUrls.MEMBER_CREATE_URL, accessToken);
		String postData = JsonUtil.bean2Json(member);
		postData = postData.replace("avatar", "avatar_mediaid");
		String result = WeChatUtil.httpsRequest(url, "POST", postData);
		logger.info(result);
		if (result != null) {
			ResultMessage resultMessage = JsonUtil.json2Bean(result, ResultMessage.class);
			return OK == resultMessage.getErrcode();
		}
		return false;
	}

	/**
	 * 更新成员 如果非必须的字段未指定，则不更新该字段之前的设置值
	 */
	public static boolean updateMember(String accessToken, Member member) throws Exception {
		String url = String.format(ApiUrls.MEMBER_UPDATE_URL, accessToken);
		String postData = JsonUtil.bean2Json(member);
		postData = postData.replace("avatar", "avatar_mediaid");
		String result = WeChatUtil.httpsRequest(url, "POST", postData);
		logger.info(result);
		if (result != null) {
			ResultMessage resultMessage = JsonUtil.json2Bean(result, ResultMessage.class);
			return OK == resultMessage.getErrcode();
		}
		return false;
	}

	/**
	 * 删除成员
	 * 
	 * @param accessToken
	 * @param userId
	 * @return
	 * @throws Exception
	 */
	public static boolean deleteMember(String accessToken, String userId) throws Exception {
		String url = String.format(ApiUrls.MEMBER_DELETE_URL, accessToken, userId);
		String result = WeChatUtil.httpsRequest(url, "GET", null);
		logger.info(result);
		if (result != null) {
			ResultMessage resultMessage = JsonUtil.json2Bean(result, ResultMessage.class);
			return OK == resultMessage.getErrcode();
		}
		return false;
	}

	/**
	 * 批量删除成员
	 * 
	 * @param accessToken
	 * @param userIds
	 * @return
	 * @throws Exception
	 */
	public static boolean deleteMembers(String accessToken, String[] userIds) throws Exception {
		String url = String.format(ApiUrls.MEMBER_BATCH_DELETE_URL, accessToken);
		String postData = JsonUtil.bean2Json(userIds);
		String result = WeChatUtil.httpsRequest(url, "POST", postData);
		logger.info(result);
		if (result != null) {
			ResultMessage resultMessage = JsonUtil.json2Bean(result, ResultMessage.class);
			return OK == resultMessage.getErrcode();
		}
		return false;
	}

	/**
	 * 创建标签
	 * 
	 * @param accessToken
	 * @param tag
	 * @return
	 * @throws Exception
	 */
	public static Tag createTag(String accessToken, Tag tag) throws Exception {
		String url = String.format(ApiUrls.CREATE_TAG_URL, accessToken);
		String postData = JsonUtil.bean2Json(tag);
		String result = WeChatUtil.httpsRequest(url, "POST", postData);
		logger.info(result);
		if (result != null) {
			Tag resultMessage = JsonUtil.json2Bean(result, Tag.class);
			return resultMessage;
		}
		return null;
	}

	/**
	 * 更新标签
	 * 
	 * @param accessToken
	 * @param tag
	 * @return
	 * @throws Exception
	 */
	public static boolean updateTag(String accessToken, Tag tag) throws Exception {
		String url = String.format(ApiUrls.UPDATE_TAG_URL, accessToken);
		String postData = JsonUtil.bean2Json(tag);
		String result = WeChatUtil.httpsRequest(url, "POST", postData);
		logger.info(result);
		if (result != null) {
			ResultMessage resultMessage = JsonUtil.json2Bean(result, ResultMessage.class);
			return OK == resultMessage.getErrcode();
		}
		return false;
	}

	/**
	 * 删除标签
	 * 
	 * @param accessToken
	 * @param tagId
	 * @return
	 * @throws Exception
	 */
	public static boolean deleteTag(String accessToken, String tagId) throws Exception {
		String url = String.format(ApiUrls.DELETE_TAG_URL, accessToken);
		String result = WeChatUtil.httpsRequest(url, "GET", null);
		logger.info(result);
		if (result != null) {
			ResultMessage resultMessage = JsonUtil.json2Bean(result, ResultMessage.class);
			return OK == resultMessage.getErrcode();
		}
		return false;
	}

	/**
	 * 获取标签成员
	 * 
	 * @param accessToken
	 * @param tagId
	 * @return
	 * @throws Exception
	 */
	public static EnterpriseResult getTagMembers(String accessToken, String tagId) throws Exception {
		String url = String.format(ApiUrls.GET_TAG_MEMBER_URL, accessToken);
		String result = WeChatUtil.httpsRequest(url, "GET", null);
		logger.info(result);
		if (result != null) {
			EnterpriseResult resultMessage = JsonUtil.json2Bean(result, EnterpriseResult.class);
			if (resultMessage.getErrcode() == 0) {
				return resultMessage;
			}

		}
		return null;
	}

	/**
	 * 增加标签成员
	 * 
	 * @param accessToken
	 * @param tagId
	 * @param userIds
	 * @param deptIds
	 * @return
	 * @throws Exception
	 */
	public static EnterpriseResult createTagMember(String accessToken, String tagId, String[] userIds, long[] deptIds) throws Exception {
		String url = String.format(ApiUrls.CREATE_TAG_MEMBER_URL, accessToken);

		StringBuilder sb = new StringBuilder();
		sb.append("{").append("\"tagid\": ").append(tagId).append(", \"userlist\": ").append(userIds).append(", \"partylist\": ").append(deptIds).append("}");
		String result = WeChatUtil.httpsRequest(url, "POST", sb.toString());
		logger.info(result);
		if (result != null) {
			EnterpriseResult resultMessage = JsonUtil.json2Bean(result, EnterpriseResult.class);
			return resultMessage;
		}
		return null;
	}

	/**
	 * 删除标签成员
	 * 
	 * @param accessToken
	 * @param tagId
	 * @param userIds
	 * @param deptIds
	 * @return
	 * @throws Exception
	 */
	public static EnterpriseResult deleteTagMember(String accessToken, String tagId, String[] userIds, long[] deptIds) throws Exception {
		String url = String.format(ApiUrls.DELETE_TAG_MEMBER_URL, accessToken);
		StringBuilder sb = new StringBuilder();
		sb.append("{").append("\"tagid\": ").append(tagId).append(", \"userlist\": ").append(userIds).append(", \"partylist\": ").append(deptIds).append("}");
		String result = WeChatUtil.httpsRequest(url, "POST", sb.toString());
		logger.info(result);
		if (result != null) {
			EnterpriseResult resultMessage = JsonUtil.json2Bean(result, EnterpriseResult.class);
			return resultMessage;
		}
		return null;
	}

	/**
	 * 获取标签列表
	 */
	public static List<Tag> getTags(String accessToken) throws Exception {
		String url = String.format(ApiUrls.DELETE_TAG_MEMBER_URL, accessToken);
		String result = WeChatUtil.httpsRequest(url, "GET", null);
		logger.info(result);
		if (result != null) {
			EnterpriseResult resultMessage = JsonUtil.json2Bean(result, EnterpriseResult.class);
			return resultMessage.getTags();
		}
		return null;
	}

	/**
	 * 消息型应用支持文本、图片、语音、视频、文件、图文等消息类型。主页型应用只支持文本消息类型，且文本长度不超过20个字
	 */
	public static boolean sendMessage(String accessToken, ECustomerMessage customerMessage) throws Exception {
		String url = String.format(ApiUrls.SEND_ACTIVE_MESSAGE_URL, accessToken);
		String postData = JsonUtil.bean2Json(customerMessage);
		logger.info(postData);
		String result = WeChatUtil.httpsRequest(url, "POST", postData);
		logger.info(result);
		if (result != null) {
			EnterpriseResult resultMessage = JsonUtil.json2Bean(result, EnterpriseResult.class);
			return OK == resultMessage.getErrcode();
		}
		return false;
	}

	/**
	 * 该接口用于向客服人员发送消息，支持文本、图片、文件消息。sender和receiver有且只有一个类型为kf。当receiver为kf时，
	 * 表示向客服发送用户咨询的问题消息。当sender为kf时，表示客服从其它IM工具回复客户，并同步消息到客服的微信上
	 */
	public static boolean sendCustomerServiceMessage(String accessToken, ECustomerServiceMessage customerServiceMessage) throws Exception {
		String url = String.format(ApiUrls.SEND_CUSTOMER_MESSAGE_URL, accessToken);
		String postData = JsonUtil.bean2Json(customerServiceMessage);
		logger.info(postData);
		String result = WeChatUtil.httpsRequest(url, "POST", postData);
		logger.info(result);
		if (result != null) {
			EnterpriseResult resultMessage = JsonUtil.json2Bean(result, EnterpriseResult.class);
			return OK == resultMessage.getErrcode();
		}
		return false;
	}

	/**
	 * 该接口使用场景为微信支付、微信红包和企业转账，企业号用户在使用微信支付的功能时，需要自行将企业号的userid转成openid。
	 * 在使用微信红包功能时，需要将应用id和userid转成appid和openid才能使用。
	 * 
	 * access_token 是 调用接口凭证 userid 是 企业号内的成员id agentid 否
	 * 整型，需要发送红包的应用ID，若只是使用微信支付和企业转账，则无需该参数
	 * 
	 * openid 企业号成员userid对应的openid，若有传参agentid，则是针对该agentid的openid。
	 * 否则是针对企业号corpid的openid appid
	 * 应用的appid，若请求包中不包含agentid则不返回appid。该appid在使用微信红包时会用到
	 */
	public static String[] userId2OpenId(String accessToken, String userId, int agentId) throws Exception {
		String url = String.format(ApiUrls.USERID_TO_OPENID_URL, accessToken);
		StringBuilder sb = new StringBuilder();
		sb.append("{").append("\"userid\": ").append(userId).append(", \"agentid\": ").append(agentId).append("}");
		String result = WeChatUtil.httpsRequest(url, "POST", sb.toString());
		logger.info(result);
		if (result != null) {
			EnterpriseResult resultMessage = JsonUtil.json2Bean(result, EnterpriseResult.class);
			if (resultMessage.getErrcode() == 0) {
				return new String[] { resultMessage.getOpenId(), resultMessage.getAppId() };
			}
		}

		return null;
	}

	/**
	 * 该接口主要应用于使用微信支付、微信红包和企业转账之后的结果查询，开发者需要知道某个结果事件的openid对应企业号内成员的信息时，
	 * 可以通过调用该接口进行转换查询 openid 是 在使用微信支付、微信红包和企业转账之后，返回结果的openid userid
	 * 该openid在企业号中对应的成员userid
	 */
	public static String openId2UserId(String accessToken, String openId) throws Exception {
		String url = String.format(ApiUrls.OPENID_TO_USERID_URL, accessToken);
		StringBuilder sb = new StringBuilder();
		sb.append("{").append("\"openid\": ").append(openId).append("}");
		String result = WeChatUtil.httpsRequest(url, "POST", sb.toString());
		logger.info(result);
		if (result != null) {
			EnterpriseResult resultMessage = JsonUtil.json2Bean(result, EnterpriseResult.class);
			if (resultMessage.getErrcode() == 0) {
				return resultMessage.getUserId();
			}
		}

		return null;
	}

	/**
	 * 通过此接口获取成员身份会有一定的时间开销。对于频繁获取成员身份的场景，建议采用如下方案：
	 * 1、企业应用中的URL链接直接填写企业自己的页面地址
	 * 2、成员跳转到企业页面时，企业校验是否有代表成员身份的cookie，此cookie由企业生成
	 * 3、如果没有获取到cookie，重定向到OAuth验证链接，获取成员身份后，由企业生成代表成员身份的cookie
	 * 4、根据cookie获取成员身份，进入相应的页面 注意，此URL的域名，必须完全匹配企业应用设置项中的
	 * '可信域名'（如果你的redirect_uri有端口号，那'可信域名'也必须加上端口号），否则跳转时会提示redirect_uri参数错误
	 * 。 员工点击后，页面将跳转至
	 * redirect_uri?code=CODE&state=STATE，企业可根据code参数获得员工的userid
	 */

	public static String getOAuth2Url(String corpId, String redirectUrl, String responseType, String scope, String state) {
		// appid 是 企业的CorpID
		// redirect_uri 是 授权后重定向的回调链接地址，请使用urlencode对链接进行处理
		// response_type 是 返回类型，此时固定为：code
		// scope 是 应用授权作用域，此时固定为：snsapi_base
		// state 否 重定向后会带上state参数，企业可以填写a-zA-Z0-9的参数值，长度不可超过128个字节
		// #wechat_redirect 是 微信终端使用此参数判断是否需要带上身份信息
		return String.format(ApiUrls.ESCOPE_CODE_OAUTH_URL, corpId, redirectUrl, responseType, scope, state);
	}

	public static String getSSO2Url(String corpId, String agentid, String redirectUrl, String state) {
		// appid 是 企业的CorpID
		// redirect_uri 是 授权后重定向的回调链接地址，请使用urlencode对链接进行处理
		// response_type 是 返回类型，此时固定为：code
		// scope 是 应用授权作用域，此时固定为：snsapi_base
		// state 否 重定向后会带上state参数，企业可以填写a-zA-Z0-9的参数值，长度不可超过128个字节
		// #wechat_redirect 是 微信终端使用此参数判断是否需要带上身份信息
		return String.format(ApiUrls.ESCOPE_CODE_SSO_URL, corpId, agentid, redirectUrl, state);
	}

	/**
	 * 通过成员授权获取到的code，每次成员授权带上的code将不一样，code只能使用一次，5分钟未被使用自动过期
	 */
	public static OpenUserIdResult getUserId(String accessToken, String code) throws Exception {
		String url = String.format(ApiUrls.GET_USERID_URL, accessToken, code);
		String result = WeChatUtil.httpsRequest(url, "GET", null);
		logger.info(result);
		if (result != null) {
			OpenUserIdResult resultMessage = JsonUtil.json2Bean(result, OpenUserIdResult.class);
			return resultMessage;
		}
		return null;

	}

	/**
	 * 获取jsApiTicket,类似accessToken
	 */
	public static JsApiTicket getJsApiTicket(String accessToken) throws Exception {
		String url = String.format(ApiUrls.JSAPI_TICKET_URL, accessToken);
		String result = WeChatUtil.httpsRequest(url, "GET", null);
		if (result != null) {
			// result = result.replace("expires_in", "expiresIn");
			JsApiTicket ticket = JsonUtil.json2Bean(result, JsApiTicket.class);
			return ticket;
		}
		return null;
	}

	// 通讯录更新
	// 通讯录更新接口提供三种更新方法：1) 增量更新成员 2）全量覆盖成员 3)
	// 全量覆盖部门。如果企业要做到与企业号通讯录完全一致，可先调用全量覆盖部门接口，再调用全量覆盖成员接口，即可保持通讯录完全一致。
	// 使用步骤为：
	// 1.下载接口对应的csv模板，如果有扩展字段，请自行添加
	// 2.按模板的格式，生成接口所需的数据文件
	// 3.通过上传媒体文件接口上传数据文件，获取media_id
	// 4.调用通讯录更新接口，传入media_id参数
	// 5.接收任务完成事件，并获取任务执行结果

	// {
	// "media_id":"xxxxxx",
	// "callback":
	// {
	// "url": "xxx",
	// "token": "xxx",
	// "encodingaeskey": "xxx"
	// }
	// }
	/**
	 * 异步任务请求参数 url 否 企业应用接收企业号推送请求的访问协议和地址，支持http或https协议 token 否 用于生成签名
	 * encodingaeskey 否 用于消息体的加密，是AES密钥的Base64编码
	 */
	public static String getBatchRequestBody(String mediaId, String url, String token, String aesKey) {
		StringBuilder sb = new StringBuilder();
		sb.append("{");
		sb.append("\"media_id\": ").append(mediaId).append(", ");
		sb.append("\"callback\": ").append("{");
		sb.append("\"url\": ").append(url).append(", ");
		sb.append("\"token\": ").append(token).append(", ");
		sb.append("\"encodingaeskey\": ").append(aesKey);
		sb.append("}");
		sb.append("}");
		return sb.toString();
	}

	// 接口说明
	// 本接口以userid为主键，增量更新企业号通讯录成员。请先下载CSV模板(下载增量更新成员模版)，根据需求填写文件内容。
	// 注意事项：
	// 1.模板中的部门需填写部门ID，多个部门用分号分隔，部门ID必须为数字
	// 2.文件中存在、通讯录中也存在的成员，更新成员在文件中指定的字段值
	// 3.文件中存在、通讯录中不存在的成员，执行添加操作
	// 4.通讯录中存在、文件中不存在的成员，保持不变
	// 5.成员字段更新规则：文件中有指定的字段，以指定的字段值为准；文件中没指定的字段，不更新
	/**
	 * 增量更新成员 异步任务id，最大长度为64字节
	 */
	public static String batchSyncUsers(String accessToken, String mediaId, String serverUrl, String token, String aesKey) throws Exception {
		String url = String.format(ApiUrls.BATCH_SYNC_USER_URL, accessToken);
		String postData = getBatchRequestBody(mediaId, serverUrl, token, aesKey);
		logger.info(postData);
		String result = WeChatUtil.httpsRequest(url, "POST", postData);
		logger.info(result);
		if (result != null) {
			EnterpriseResult resultMessage = JsonUtil.json2Bean(result, EnterpriseResult.class);
			if (resultMessage.getErrcode() == 0) {
				return resultMessage.getJobId();
			}
		}
		return null;
	}

	// 本接口以userid为主键，全量覆盖企业号通讯录成员，任务完成后企业号通讯录成员与提交的文件完全保持一致。请先下载CSV文件(下载全量覆盖成员模版)，根据需求填写文件内容。
	// 注意事项：
	// 1.模板中的部门需填写部门ID，多个部门用分号分隔，部门ID必须为数字
	// 2.文件中存在、通讯录中也存在的成员，完全以文件为准
	// 3.文件中存在、通讯录中不存在的成员，执行添加操作
	// 4.通讯录中存在、文件中不存在的成员，执行删除操作。出于安全考虑，如果:
	// a) 需要删除的成员多于50人，且多于现有人数的20%以上
	// b) 需要删除的成员少于50人，且多于现有人数的80%以上
	// 系统将中止导入并返回相应的错误码
	// 5.成员字段更新规则：文件中有指定的字段，以指定的字段值为准；文件中没指定的字段，不更新
	/**
	 * 全量覆盖成员
	 * 
	 */
	public static String batchReplaceUsers(String accessToken, String mediaId, String serverUrl, String token, String aesKey) throws Exception {
		String url = String.format(ApiUrls.BATCH_REPLACE_USER_URL, accessToken);
		String postData = getBatchRequestBody(mediaId, serverUrl, token, aesKey);
		logger.info(postData);
		String result = WeChatUtil.httpsRequest(url, "POST", postData);
		logger.info(result);
		if (result != null) {
			EnterpriseResult resultMessage = JsonUtil.json2Bean(result, EnterpriseResult.class);
			if (resultMessage.getErrcode() == 0) {
				return resultMessage.getJobId();
			}
		}
		return null;
	}

	// 接口说明
	// 本接口以partyid为键，全量覆盖企业号通讯录组织架构，任务完成后企业号通讯录组织架构与提交的文件完全保持一致。请先下载CSV文件(下载全量覆盖部门模版)，根据需求填写文件内容。
	// 注意事项：
	// 1.文件中存在、通讯录中也存在的部门，执行修改操作
	// 2.文件中存在、通讯录中不存在的部门，执行添加操作
	// 3.文件中不存在、通讯录中存在的部门，当部门下没有任何成员或子部门时，执行删除操作
	// 4.CSV文件中，部门名称、部门ID、父部门ID为必填字段，部门ID必须为数字；排序为可选字段，置空或填0不修改排序
	/**
	 * 全量覆盖部门
	 */
	public static String batchReplaceParty(String accessToken, String mediaId, String serverUrl, String token, String aesKey) throws Exception {
		String url = String.format(ApiUrls.BATCH_REPLACE_PARTY_URL, accessToken);
		String postData = getBatchRequestBody(mediaId, serverUrl, token, aesKey);
		logger.info(postData);
		String result = WeChatUtil.httpsRequest(url, "POST", postData);
		logger.info(result);
		if (result != null) {
			EnterpriseResult resultMessage = JsonUtil.json2Bean(result, EnterpriseResult.class);
			if (resultMessage.getErrcode() == 0) {
				return resultMessage.getJobId();
			}
		}
		return null;
	}

	/**
	 * 获取异步任务结果
	 */

	// JobResult
	public static JobResult getJobResult(String accessToken, String mediaId, String jobId) throws Exception {
		String url = String.format(ApiUrls.BATCH_JOB_RESULT_URL, accessToken, jobId);
		String result = WeChatUtil.httpsRequest(url, "GET", null);
		logger.info(result);
		if (result != null) {
			JobResult resultMessage = JsonUtil.json2Bean(result, JobResult.class);
			return resultMessage;
		}
		return null;
	}

	/**
	 * 媒体文件类型，分别有图片（image）、语音（voice）、视频（video），普通文件(file) media 是
	 * form-data中媒体文件标识，有filename、filelength、content-type等信息
	 */
	public static UploadMediaResult uploadTempMedia(String accessToken, File file, String mediaType) throws Exception {
		String url = String.format(ApiUrls.UPLOAD_TEMP_MEDIA_URL, accessToken, mediaType);
		String result = WeChatUtil.upload(url, file);
		if (result != null) {
			UploadMediaResult uploadMediaResult = JsonUtil.json2Bean(result, UploadMediaResult.class);
			return uploadMediaResult;
		}

		return null;
	}

	/**
	 * 通过media_id获取图片、语音、视频等文件，协议和普通的http文件下载完全相同。该接口即原"下载多媒体文件"接口。
	 */
	public static DownloadMediaResult downMedia(String accessToken, String mediaId) throws Exception {
		String url = String.format(ApiUrls.DOWNLOAD_TEMP_MEDIA_URL, accessToken, mediaId);
		DownloadMediaResult downloadMediaResult = WeChatUtil.downloadMedia(url);
		return downloadMediaResult;
	}

	/**
	 * 创建会话
	 */
	// chatid 是 会话id。字符串类型，最长32个字符。只允许字符0-9及字母a-zA-Z,
	// 如果值内容为64bit无符号整型：要求值范围在[1, 2^63)之间， [2^63, 2^64)为系统分配会话id区间
	// name 是 会话标题
	// owner 是 管理员userid，必须是该会话userlist的成员之一
	// userlist 是 会话成员列表，成员用userid来标识。会话成员必须在3人或以上，1000人以下
	public static boolean createChat(String accessToken, Chat chat) throws Exception {
		String url = String.format(ApiUrls.CEATE_CHAT_URL, accessToken);
		String postData = JsonUtil.bean2Json(chat);
		String result = WeChatUtil.httpsRequest(url, "POST", postData);
		logger.info(result);
		if (result != null) {
			EnterpriseResult resultMessage = JsonUtil.json2Bean(result, EnterpriseResult.class);
			return resultMessage.getErrcode() == 0;
		}
		return false;
	}

	/**
	 * 获取会话信息
	 * 
	 * @param accessToken
	 * @param chatId
	 * @return
	 * @throws Exception
	 */
	public static EnterpriseResult getChat(String accessToken, String chatId) throws Exception {
		String url = String.format(ApiUrls.GET_CHAT_URL, accessToken, chatId);
		String result = WeChatUtil.httpsRequest(url, "GET", null);
		logger.info(result);
		if (result != null) {
			EnterpriseResult resultMessage = JsonUtil.json2Bean(result, EnterpriseResult.class);
			return resultMessage;
		}
		return null;
	}

	/**
	 * 修改会话信息
	 */
	// chatid 是 会话id
	// op_user 是 操作人userid
	// name 否 会话标题
	// owner 否 管理员userid，必须是该会话userlist的成员之一
	// add_user_list 否 会话新增成员列表，成员用userid来标识
	// del_user_list 否 会话退出成员列表，成员用userid来标识
	public static boolean updateChat(String accessToken, Chat chat) throws Exception {
		String url = String.format(ApiUrls.UPDATE_CHAT_URL, accessToken);
		String postData = JsonUtil.bean2Json(chat);
		logger.info(postData);
		String result = WeChatUtil.httpsRequest(url, "POST", postData);
		logger.info(result);
		if (result != null) {
			EnterpriseResult resultMessage = JsonUtil.json2Bean(result, EnterpriseResult.class);
			return resultMessage.getErrcode() == 0;
		}
		return false;
	}

	/**
	 * 退出会话
	 * 
	 * @param accessToken
	 * @param chat
	 * @return
	 * @throws Exception
	 */
	// chatid 是 会话id
	// op_user 是 操作人userid
	public static boolean quitChat(String accessToken, Chat chat) throws Exception {
		String url = String.format(ApiUrls.QUIT_CHAT_URL, accessToken);
		String postData = JsonUtil.bean2Json(chat);
		String result = WeChatUtil.httpsRequest(url, "POST", postData);
		logger.info(result);
		if (result != null) {
			EnterpriseResult resultMessage = JsonUtil.json2Bean(result, EnterpriseResult.class);
			return resultMessage.getErrcode() == 0;
		}
		return false;
	}

	/**
	 * 发送消息
	 * 消息支持文本、图片、文件，在发送时需要区分群聊和单聊。如果接收人不存在，则发送失败。在企业IM端发送的消息，在同步到发送者的微信上时
	 * ，不会有提醒。 可以通过文本消息下发表情（下载微信表情转换表）
	 * 
	 * @throws Exception
	 */

	public static boolean sendChatMessage(String accessToken, ChatMessage chatMessage) throws Exception {
		String url = String.format(ApiUrls.SEND_CHAT_URL, accessToken);
		String postData = JsonUtil.bean2Json(chatMessage);
		String result = WeChatUtil.httpsRequest(url, "POST", postData);
		logger.info(result);
		if (result != null) {
			EnterpriseResult resultMessage = JsonUtil.json2Bean(result, EnterpriseResult.class);
			return resultMessage.getErrcode() == 0;
		}
		return false;
	}

	public static void main(String[] args) throws Exception {
		String corpId = "wx406ea2215654009e";
//		String corpSecret = "RxRdK6a_Tjj6OeVDTBOMi_q0qIMg6C1j_WNK-QanVmseOLQyEFamtuD_9P8h2RFQ";
		String customerSecret = "KOiRWlSakrNUXjVK1mfk5zbDy8wEZfCh_13AcD_3L73um-LYeKKy-1gJaLkOziRY";
//		AccessToken accessToken = getAccessToken(corpId, customerSecret);
//		System.out.println(accessToken);
		// AccessToken
		// [getToken()=L8AOg99uzgGjI7yAm0d3XwpP5fs3wEfqDI0keNOOh8j2HPZ-PZ3DQiB91A9UydHJ,
		// getExpiresIn()=7200, getErrcode()=0, getErrmsg()=ok]

		// String accessToken =
		// "2_VrkRPsQoyMsmjpZeSwgU1qFpwX1OLy5WnPefXDpUzu7IdAcoNmhpXaP4uY2493";
		// List<Department> departments = getDepartments(accessToken,
		// "0");
		// System.out.println(departments);
		// 0-[Department [id=4, name=北京服务一部, parentId=1, order=400]]
		// Department department = new Department();
		// department.setName("北京服务三部");
		// department.setParentId(1);
		// department.setOrder(402);
		// department.setId(5);
		// department = createDepartment(accessToken, department);
		// // System.out.println(department);
		// boolean flag = updateDepartment(accessToken, department);
		// System.out.println(flag);
		//
		// flag = deleteDepartment(accessToken, "7");
		//
		// List<Department> departments = getDepartments(accessToken,
		// "0");
		// System.out.println(departments);

		// [Member [userId=null, name=张大树, departIds=[4], position=null,
		// mobile=15311414081, gender=0, tel=null, email=null,
		// weiXinId=null, avatar=null, status=1, enable=null,
		// extAttrs=[]],
		// Member [userId=null, name=adopapa, departIds=[4],
		// position=null, mobile=15311288182, gender=0, tel=null,
		// email=null, weiXinId=null,
		// avatar=http://shp.qpic.cn/bizmp/o7RWU6JwStUfwrU89OA4jwh0ibGcGySBS2oIxhOrbGyj4ARgqMze0AA/,
		// status=1, enable=null, extAttrs=[]]]

		// Member member = new Member();
		// member.setDepartIds(new Integer[]{4});
		// member.setEmail("dreammore5156@163.com");
		// member.setGender("0");
		// member.setUserId("dreammore");
		// member.setName("dreammore");

		// boolean result = createMember(accessToken, member);
		// System.err.println(result);

		// List<Member> members = getMembersByDepartment(accessToken,
		// "1", 1, 0);
		// System.out.println(members.size());
		// members = getMembersByDepartment(accessToken, "4", true, 0);
		// System.err.println(members);

		// Member member = getMember(accessToken, "dreammore");
		// System.out.println(member);
//		String accessToken = "Gn4Dql6NW0bgAoySeNuWDxDV-l-Y612qjSYeFrZ64yKJuRKGUQTEs6zqCmqPnwpn";
//		String senderId = "d123456";
//		String senderType = Operator.KF_OPERATOR_TYPE;
//		String receiverId = "F001";
//		String receiverType = Operator.USERID_OPERATOR_TYPE;
//		String content = "测试一下吧";
//		ECustomerServiceMessage customerServiceMessage = ECustomerServiceMessage.getTextCustomerServiceMessage(senderId, senderType, receiverId, receiverType, content);
//		boolean send = EWechatApi.sendCustomerServiceMessage(accessToken, customerServiceMessage);
//		System.out.println(send);
//		AccessToken accessToken = EWechatApi.getAccessToken(corpId, "EN_7SeIUm5rZ7gJ2heQXbivIVVETq1jKdDbHqMq5zbTHCJjM0X_FqcFw5-Nl9zw7");
//		System.out.println(accessToken);
//		ChatMessage chatMessage = ChatMessage.getTextChatMessage("20160731170757594", "F001", false, "测试一下吧");
////		EWechatApi.sendChatMessage("9H17si09ylJ9H8yG61VT9tuSbCfO8tvdH5QooXtVfA9SNmO0rOg5dkBde9SKzsAN", chatMessage);
//		EWechatApi.sendChatMessage(accessToken.getToken(), chatMessage);
		
		
		String result = "{\"errcode\":0,\"errmsg\":\"ok\",\"userid\":\"AiBao\",\"name\":\"艾宝\",\"department\":[6],\"mobile\":\"13679409030\",\"gender\":\"1\",\"avatar\":\"http://shp.qpic.cn/bizmp/o7RWU6JwStXkziaibqiaI84OG7k9M4fDg4QYqG2v6HuXIWW0BCcpcoSFA/\",\"status\":1,\"extattr\":{\"attrs\":[{\"name\":\"座机\",\"value\":\"\"},{\"name\":\"英文名\",\"value\":\"\"}]}}";
		Member member = JsonUtil.json2Bean(result, Member.class);
		System.out.println(member);
	}

}
